/*
 * Copyright (c) zhg2yqq.com Corp.
 * All Rights Reserved.
 */
package com.zhg2yqq.wheels.security.decision;

import java.util.Collection;
import java.util.stream.Collectors;

import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.FilterInvocation;

import com.zhg2yqq.wheels.common.dto.CurrentUserDTO;
import com.zhg2yqq.wheels.security.constants.SecurityConstants;

/**
 * @author zhg2yqq, 2022年11月28日
 * @version zhg2yqq v1.0
 */
public class UrlAccessDecisionManager implements AccessDecisionManager {

    /**
     * @param authentication: 当前登录用户的角色信息
     * @param object:         请求url信息
     * @param collection:     `UrlFilterInvocationSecurityMetadataSource`中的getAttributes方法传来的，表示当前请求需要的角色（可能有多个）
     * @return: void
     */
    @Override
    public void decide(Authentication authentication, Object object,
                       Collection<ConfigAttribute> collection)
            throws AccessDeniedException, AuthenticationException {
        if (collection.isEmpty()) {
            return;
        }
        if (authentication.getPrincipal() instanceof CurrentUserDTO) {
            CurrentUserDTO user = (CurrentUserDTO) authentication.getPrincipal();
            if (SecurityConstants.SUPER_ID.equals(user.getId())) {
                return;
            }
        }
        // 当前用户所具有的角色
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        // 遍历适配的角色
        for (ConfigAttribute ca : collection) {
            // 当前url请求需要的权限
            String needRole = ca.getAttribute();

            for (GrantedAuthority authority : authorities) {
                // 只要包含其中一个角色即可访问
                if (authority.getAuthority().equals(needRole)) {
                    return;
                }
            }
        }
        throw new AccessDeniedException("请联系管理员分配权限！" + collection.stream().map(ConfigAttribute::getAttribute).collect(Collectors.joining(",", "[", "]")));
    }

    @Override
    public boolean supports(ConfigAttribute configAttribute) {
        return true;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

}
